import inspect
from typing import Callable, Optional, Dict

from model.action import Action
from model.delay import Delay
from model.state import State


class Transition:
    def __init__(self, source_state: State, target_state: State, name:str, delay:Delay,
                 probability:float, act:Optional[Action],
                 guard:Optional[Callable[[Action, Dict], bool]] = None,
                 inhibition:Optional[Callable[[Action, Dict], bool]] = None,
                 update:Optional[Callable[[Action, Dict], Dict]] = None):
        self.source_state = source_state
        self.target_state = target_state
        self.name = name
        self.delay = delay
        self.probability = probability
        self.act = act
        self.guard = guard
        self.inhibition = inhibition
        self.update = update
    
    def __str__(self) -> str:
        """Return a string representation of the transition."""
        delay_str = "\nDelay | " + str(self.delay)
        probability_str = "\nProbability | " + str(self.probability)
        action_str = "\nAction | " + str(self.act) if self.act else ""
        guard_str = "\nGuard | " + inspect.getsource(self.guard).strip() if self.guard else ""
        inhibition_str = "\nInhibition | "+ inspect.getsource(self.inhibition).strip() if self.inhibition else ""
        update_str = "\nUpdate | " + inspect.getsource(self.update).strip() if self.update else ""
        return '''{} {} {} {} {} {} {}'''.format(
                self.name, delay_str, probability_str, action_str, guard_str, inhibition_str, update_str).replace(":", "?" )

    def __hash__(self) -> int:
        return hash(str(self.source_state)+str(self.target_state)+ self.name)

    def get_current_state(self) -> State:
        return self.source_state

    def get_target_state(self) -> State:
        return self.target_state

if __name__ == "__main__":
    attr = {
        "host": "n2",
        "backup": "n3" 
    }
    s0 = State("host backup work", True)
    s1 = State("host work backup fail", False)
    t1 = Transition(s0, s1, "host fail", Delay("instant"), 1,
                    Action("s1", "host fail", "passive"),
                    lambda a, d: a == "{} fail active".format(d["host"]),
                    None, None)
        
    print(t1)